#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
#define MAX_EVENTS 2

// 消息类型定义
#define MSG_PUBLIC 1      // 公共消息
#define MSG_PRIVATE 2     // 私聊消息
#define MSG_SYSTEM 3      // 系统消息
#define MSG_JOIN 4        // 加入聊天室
#define MSG_LEAVE 5       // 离开聊天室
#define MSG_RENAME 6      // 改名
#define MSG_LOGIN 7       // 登录请求
#define MSG_REGISTER 8    // 注册请求
#define MSG_AUTH_RESULT 9 // 认证结果

typedef struct
{
    int type;           // 消息类型
    char sender[32];    // 发送者
    char content[1024]; // 消息内容
    char target[32];    // 目标（私聊时使用）
    char password[32];  // 密码（登录注册时使用）
} chat_message;

// 全局变量
int sockfd;
char username[32] = "用户";
int running = 1;
int is_logged_in = 0; // 是否已登录

// 设置非阻塞
void set_nonblocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

// 处理服务器消息
void handle_server_message(chat_message *msg)
{
    switch (msg->type)
    {
    case MSG_PUBLIC:
        printf("[%s] %s\n", msg->sender, msg->content);
        break;
    case MSG_PRIVATE:
        printf("[私聊来自 %s] %s\n", msg->sender, msg->content);
        break;
    case MSG_SYSTEM:
        printf("[系统] %s\n", msg->content);
        break;
    case MSG_JOIN:
        printf("*** %s 加入了聊天室 ***\n", msg->sender);
        break;
    case MSG_LEAVE:
        printf("*** %s 离开了聊天室 ***\n", msg->sender);
        break;
    case MSG_AUTH_RESULT:
        printf("[认证] %s\n", msg->content);
        if (strstr(msg->content, "Login successful") != NULL)
        {
            is_logged_in = 1;
            strncpy(username, msg->target, 31);
            username[31] = '\0';
            system("clear");
            printf("成功登录为: %s\n", username);
            printf("\n客户端命令格式：\n");
            printf("公共消息: /msg <内容>\n");
            printf("私聊消息: /private <目标用户> <内容>\n");
            printf("改名: /nick <新名字>\n");
            printf("列出用户: /list\n");
            printf("退出: /quit\n");
            printf("登录: /login <用户名> <密码>\n");
            printf("注册: /register <用户名> <密码>\n");
        }
        break;
    }
}

// 解析用户输入
void parse_input(char *input, chat_message *msg)
{
    memset(msg, 0, sizeof(chat_message));
    char *token = strtok(input, " ");

    if (token == NULL)
    {
        return;
    }

    if (strcmp(token, "/quit") == 0)
    {
        running = 0;
        return;
    }
    // 未登录状态只能进行登录和注册操作
    else if (!is_logged_in)
    {
        if (strcmp(token, "/login") == 0)
        {
            memset(msg, 0, sizeof(msg));
            msg->type = MSG_LOGIN;
            char *user = strtok(NULL, " ");
            char *pass = strtok(NULL, " ");
            if (user && pass)
            {
                strncpy(username, user, 31); // 临时保存用户名
                username[31] = '\0';
                strncpy(msg->sender, user, 31);
                strncpy(msg->password, pass, 31);
                msg->sender[31] = '\0';
                msg->password[31] = '\0';
            }
        }
        else if (strcmp(token, "/register") == 0)
        {
            msg->type = MSG_REGISTER;
            char *user = strtok(NULL, " "); // 先保存用户名指针
            char *pass = strtok(NULL, " ");
            if (user && pass)
            {
                strncpy(username, user, 31); // 然后再复制到 username
                username[31] = '\0';
                strncpy(msg->sender, user, 31);
                strncpy(msg->password, pass, 31);
                msg->sender[31] = '\0';
                msg->password[31] = '\0';
            }
        }
        else
        {
            printf("请先登录或注册！\n");
            printf("使用方法：\n");
            printf("/login <用户名> <密码>\n");
            printf("/register <用户名> <密码>\n");
        }
        return; // 确保未登录状态下不会执行到函数最后
    }
    // 已登录状态可以使用其他功能

    else if (strcmp(token, "/msg") == 0)
    {
        msg->type = MSG_PUBLIC;
        memset(msg->target, 0, sizeof(msg->target));
        char *content = strtok(NULL, "");
        if (content != NULL)
        {
            strncpy(msg->content, content, 1023);
            msg->content[1023] = '\0';
        }
    }
    else if (strcmp(token, "/private") == 0)
    {
        msg->type = MSG_PRIVATE;
        char *target = strtok(NULL, " ");
        if (target != NULL)
        {
            strncpy(msg->target, target, 31);
            msg->target[31] = '\0';
            char *content = strtok(NULL, "");
            if (content != NULL)
            {
                strncpy(msg->content, content, 1023);
                msg->content[1023] = '\0';
            }
        }
    }
    else
    {
        // 默认作为公共消息
        msg->type = MSG_PUBLIC;
        strncpy(msg->content, input, 1023);
        msg->content[1023] = '\0';
    }

    // 只有已登录状态才需要设置发送者
    if (is_logged_in)
    {
        strncpy(msg->sender, username, 31);
        msg->sender[31] = '\0';
    }
}

int main()
{
    struct sockaddr_in server_addr;
    char input[BUFFER_SIZE];
    chat_message msg;

    // 创建socket
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("创建套接字失败");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0)
    {
        perror("地址转换失败");
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("连接服务器失败");
        exit(EXIT_FAILURE);
    }

    // 设置非阻塞
    set_nonblocking(sockfd);
    set_nonblocking(STDIN_FILENO);

    // 创建epoll实例
    int epoll_fd = epoll_create1(0);
    if (epoll_fd < 0)
    {
        perror("创建epoll实例失败");
        exit(EXIT_FAILURE);
    }

    // 添加socket和stdin到epoll
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = sockfd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &event) < 0)
    {
        perror("epoll控制失败");
        exit(EXIT_FAILURE);
    }

    event.data.fd = STDIN_FILENO;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) < 0)
    {
        perror("epoll控制失败");
        exit(EXIT_FAILURE);
    }

    printf("已连接到聊天服务器。\n");
    printf("请先登录或注册：\n");
    printf("/login <用户名> <密码>\n");
    printf("/register <用户名> <密码>\n");

    // 主循环
    struct epoll_event events[MAX_EVENTS];

    while (running)
    {

        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);

        for (int i = 0; i < n; i++)
        {
            if (events[i].data.fd == sockfd)
            {
                // 处理服务器消息
                ssize_t bytes_read = read(sockfd, &msg, sizeof(msg));
                if (bytes_read > 0 && bytes_read == sizeof(msg))
                {
                    handle_server_message(&msg);
                }
                else if (bytes_read == 0)
                {
                    printf("服务器断开连接\n");
                    running = 0;
                    break;
                }
            }
            else if (events[i].data.fd == STDIN_FILENO)
            {
                // 处理用户输入
                if (fgets(input, BUFFER_SIZE, stdin) != NULL)
                {
                    input[strcspn(input, "\n")] = '\0'; // 移除换行符

                    memset(&msg, 0, sizeof(msg));
                    parse_input(input, &msg);

                    if (msg.type != 0 && running)
                    {
                        printf("发送输入消息\n");
                        ssize_t bytes_written = write(sockfd, &msg, sizeof(msg));
                        if (bytes_written != sizeof(msg))
                        {
                            perror("写入不完整");
                        }
                    }
                }
            }
        }
    }

    // 清理
    close(sockfd);
    close(epoll_fd);
    return 0;
}
